home *** CD-ROM | disk | FTP | other *** search
- /* fd2lib by Volker Barthelmann */
- /* rework 09/96 by Johnny Teveßen <j.tevessen@line.org> */
- /* PPC version by Volker Barthelmann in 12/97 */
-
- /* "T:"s removed: Not very portable!
- */
-
- #define NDEBUG
-
- #ifdef _DCC
- # define CTYPE_NEAR
- #endif
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <stdarg.h>
-
- const char VersTag[] = "\0$VER: fd2libPPC 0.1 (21.12.1997)"; /* AmigaOS version string. Doesn't hurt... */
-
- #define MAXLINELEN 1000
- #define BUFFEREDLEN 16384 /* 1024 is standard */
-
- #define NUMREGS 16
-
- static const char *regnames[NUMREGS] =
- {
- "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
- "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"
- };
-
- enum
- {
- A0=0, A1, A2, A3, A4, A5, A6, A7,
- D0 , D1, D2, D3, D4, D5, D6, D7
- };
-
- #define SMALLCODE 1 /* not available for PPC */
- #define SMALLDATA 2
- #define FASTCALL 4 /* not available for PPC */
- #define NEWNOTATE 8 /* not available for PPC */
- #define VARGSLOGIC 16
- #define DEBUG 32
-
- #ifndef TRUE
- typedef short BOOL;
- # define TRUE 1
- # define FALSE 0
- #endif
-
- #ifndef NULL
- # define NULL ((void *)0L)
- #endif
-
- #ifdef __GNUC__
- # define gnuspec(x) x
- #else
- # define gnuspec(x)
- #endif
-
- #define NORETURN gnuspec(__attribute__ ((noreturn)))
-
- static const char *varargs[] =
- {
- #include "vargs.h"
- NULL, NULL
- };
-
- static void ExitFailure(const char *, const char *) NORETURN;
-
- static void
- ExitFailure(const char *cause, const char *insertme)
- {
- fprintf(stderr, cause, insertme);
-
- exit(EXIT_FAILURE);
- }
-
- static void
- check(const char *ptr)
- {
- if(!*ptr)
- {
- ExitFailure("Unexpected EOL\n", NULL);
- }
- }
-
- static void warnhim(int linenr, const char *format, ...) gnuspec(__attribute__ ((format (printf, 2, 3))));
-
- static void
- warnhim(int linenr, const char *format, ...)
- {
- char linebuf[250];
- va_list vl;
-
- va_start(vl,format);
- vsprintf(linebuf, format, vl);
- va_end(vl);
-
- fprintf(stderr, "Warning line %d: %s\n", linenr, linebuf);
- }
-
- static FILE *
- OpenLVO(const char *name, const char *outdir, const char *outform)
- {
- FILE *lvos;
- char lvoname[MAXLINELEN];
-
- strcpy(lvoname, outdir);
-
- if(name)
- {
- char *k = (char *)name, *p;
- int lvonamlen;
-
- if((p = strrchr(k, '/')) != NULL) k = p + 1;
- if((p = strrchr(k, ':')) != NULL) k = p + 1;
-
- strcat(lvoname, k);
-
- lvonamlen = strlen(lvoname);
-
- if((lvonamlen > 7) && !strcmp(lvoname+lvonamlen-7, "_lib.fd"))
- {
- lvoname[lvonamlen-7] = '\0';
- }
- else if((lvonamlen > 3) && !strcmp(lvoname+lvonamlen-3, ".fd"))
- {
- lvoname[lvonamlen-3] = '\0';
- }
-
- strcat(lvoname, "_lvo.s");
- }
- else
- {
- strcat(lvoname, "fd_lvo.s");
- }
-
- printf(outform, lvoname, lvoname, lvoname);
-
- lvos = fopen(lvoname, "w");
-
- return(lvos);
- }
-
- static void
- ProcessFD(const char *name, int mode, const char *outdir, const char *outform)
- {
- FILE *fd, *lvos;
- FILE *out;
- int offset = 0, i, j, count, savecount;
- char function[80], tmpfuncnam[80], ff[MAXLINELEN+8], base[50];
- char line[MAXLINELEN];
- register char *p;
- char *functionp;
- int reg[NUMREGS], loops, linenr = 0;
- BOOL public = -1; /* Why FALSE? */
-
- /* "-1" is the initial value for "public". It means:
- ** no statement yet.
- */
-
- *function = *base = *line = '\0';
-
- if(name) fd = fopen(name, "r");
- else fd = stdin;
-
- if(!fd) ExitFailure("Could not open `%s'\n", name);
-
- setvbuf(fd, NULL, _IOFBF, BUFFEREDLEN); /* maybe _IOLBF? */
-
- if(!(lvos = OpenLVO(name, outdir, outform)))
- ExitFailure("Could not create lvo file\n", NULL);
-
- setvbuf(lvos, NULL, _IOFBF, BUFFEREDLEN);
-
- for(;;)
- {
- char *k;
-
- if(!fgets(line, MAXLINELEN-1, fd)) ExitFailure("Unexpected EOF\n", NULL);
-
- linenr ++;
-
- if((*line == '*') || !*line) continue;
-
- switch(*line + line[2])
- {
- case ('#'+'b'):
- if(!strncmp(line, "##base", 6))
- {
- if(*base) warnhim(linenr, "##base detected more than once!");
-
- p = line+6; while(isspace(*p)) p++;
- k = base ; while(isgraph(*p)) *k++ = *p++;
-
- *k = '\0';
-
- if(mode & DEBUG) printf("Base set to `%s'\n", base);
- continue;
- }
-
- if(!strncmp(line, "##bias", 6))
- {
- p = line+6; while(isspace(*p)) p++;
- sscanf(p, "%i", &offset);
-
- if(mode & DEBUG) printf("Bias set to -%d\n", offset);
- continue;
- }
- break;
-
- case ('#'+'p'):
- if(!strncmp(line, "##public", 8))
- {
- if(public == TRUE) warnhim(linenr, "##public after ##public detected!");
- else public = TRUE;
-
- if(mode & DEBUG) printf("Turned on public mode at bias -%d\n", offset);
- continue;
- }
-
- if(!strncmp(line, "##private", 9))
- {
- if(public == FALSE) warnhim(linenr, "##private after ##private detected!");
- else public = FALSE;
-
- if(mode & DEBUG) printf("Turned off public mode at bias -%d\n", offset);
- continue;
- }
- break;
-
- case ('#'+'e'):
- if(!strncmp(line, "##end", 5)) return;
- break;
- }
-
- if(*line == '#')
- {
- warnhim(linenr, "Unknown directive: `%s'!", line);
- continue;
- }
-
- if(!public)
- {
- offset += 6;
- continue;
- }
-
- if(public == -1)
- {
- warnhim(linenr, "Neither ##public nor ##private specified yet. Assuming ##public.");
- public = TRUE;
- }
-
- functionp = function;
-
- for(loops=0; loops<=1; loops++)
- {
- char *p = line; char *k = functionp;
-
- while(isspace(*p)) p++;
-
- if(!loops)
- {
- while((*p != '(') && *p) *k++ = *p++;
-
- check(p);
- *k = '\0';
-
- fprintf(lvos, "\t.set\tLVO%s,-%d\n"
- "\t.global\tLVO%s\n",
- functionp, offset, functionp
- );
- }
- else
- {
- while((*p != '(') && *p) p++;
- check(p);
- }
-
- if(mode & DEBUG) printf("function=%s, loops=%d\n", functionp, loops);
-
- /* Open function stub source file */
-
- sprintf(ff, "%s%s.s", outdir, functionp);
-
- printf(outform, ff, ff, ff);
-
- out = fopen(ff, "w");
- if(!out) ExitFailure("Could not create <%s>\n", functionp);
- setvbuf(out, NULL, _IOFBF, BUFFEREDLEN);
-
- /* Write assembler headers */
-
- fprintf(out,"\t.text\n");
- if(*base) fprintf(out, "\t.global\t%s\n", base+1);
- fprintf(out,"\t.global\tPPCCallOS\n");
- fprintf(out,"\t.global\t%s\n",functionp);
-
- /* Set all registers to 'unused' */
-
- for(i=0; i<NUMREGS; i++) reg[i] = 0;
-
- /* Skip argument names */
-
- while((*p!=')') && *p) p++;
-
- check(p);
- p++;
-
- /* Search for beginning of register list */
-
- while((*p!='(') && *p) p++;
-
- check(p);
- p++;
-
- /* Scan register list */
-
- count = savecount = 0;
-
- while((*p!=')') && *p)
- {
- /* Check whether register description is valid */
-
- if((!((*p=='a') || (*p=='A') || (*p=='d') || (*p=='D'))) || !((p[1]>='0') && (p[1]<='7')))
- ExitFailure("Bad register description\n", NULL);
-
- /* Convert description to internal enum format */
- /* Corrected: 'A' was not recognized */
-
- if((*p=='a') || (*p=='A')) j = p[1] - '0';
- else j = p[1] - ('0'-8);
-
- /* Mark register as used and save its argument counter */
-
- reg[j] = ++count;
-
- /* Increase counter if register has to be saved */
-
- if(!(j==A0 || j==A1 || j==A6 || j==D0 || j==D1))
- savecount ++;
-
- /* Search for next register */
-
- p += 2;
- while(isspace(*p) && *p) p++;
-
- if((*p == '/') || (*p==',')) p++;
- else if(*p != ')') ExitFailure("Parse error - ')' expected\n", NULL);
-
- while(isspace(*p) && *p) p++;
-
- check(p);
- }
-
- fprintf(out,"\t.align\t3\n%s:\n",functionp);
- if(!loops){
- fprintf(out,"\tstwu\t1,-96(1)\n\tmflr\t11\n\tstw\t11,100(1)\n");
- }else{
- int i;
- /* Hack the stack-frame for varargs. */
- /* Build stack-frame, but save LR in our own stack-frame, */
- /* because we have to overwrite the lower 8 bytes of the */
- /* caller's frame. */
- fprintf(out,"\tstwu\t1,-128(1)\n\tmflr\t11\n\tstw\t11,100(1)\n");
- /* Save the caller's saved SP in our own stack-frame. */
- fprintf(out,"\tlwz\t11,128(1)\n\tstw\t11,96(1)\n");
- /* Store r3-r8 at the top of our stack-frame and r9-r10 */
- /* at the low 8 bytes of the caller's frame. This way all */
- /* arguments will reside in one continuous area. */
- for(i=3+count-1;i<=10;i++)
- fprintf(out,"\tstw\t%d,%d(1)\n",i,104+4*(i-3));
- }
- for(i=0; i<NUMREGS; i++) /* Registers */
- {
- if(reg[i])
- {
- if(!loops||reg[i]<count){
- if(reg[i]<=8)
- fprintf(out,"\tstw\t%d,",reg[i]+2);
- else
- fprintf(out,"\tlwz\t11,%d(1)\n\tstw\t11,",reg[i]*4+4-8*4);
- }else{
- fprintf(out,"\taddi\t11,1,%d\n\tstw\t11,",100+count*4);
- }
-
- if(i<=7)
- fprintf(out,"%d(1)\n",68+4*i);
- else
- fprintf(out,"%d(1)\n",36+4*(i-8));
-
-
- }
- } /* for i */
-
- /* Now place the real function call */
-
- fprintf(out,"\tli\t11,-%d\n\tstw\t11,8(1)\n",offset);
- fprintf(out,"\tli\t11,1\n\tstw\t11,12(1)\n\tstw\t11,24(1)\n");
- fprintf(out,"\tlis\t11,%s@ha\n\tlwz\t11,%s@l(11)\n\tstw\t11,92(1)\n",base+1,base+1);
- fprintf(out,"\taddi\t3,1,8\n\tbl\tPPCCallOS\n");
- if(!loops){
- fprintf(out,"\tlwz\t11,100(1)\n\tmtlr\t11\n");
- fprintf(out,"\taddi\t1,1,96\n\tblr\n");
- }else{
- /* Varargs. Rebuild the caller's stack-frame. */
- fprintf(out,"\tlwz\t11,96(1)\n\tstw\t11,128(1)\n");
- fprintf(out,"\tlwz\t11,100(1)\n\tmtlr\t11\n");
- fprintf(out,"\taddi\t1,1,128\n\tblr\n");
- }
- fclose(out);
-
- if(loops != 0) break;
-
- p = (char *) *varargs;
- loops = 3;
-
- if(mode & DEBUG) printf("Searching function `%s' in vargs table...\n", functionp);
-
- if(p != NULL)
- {
- if(mode & VARGSLOGIC)
- {
- int fnlen = strlen(functionp);
-
- if((fnlen > 7) && (!strcmp(functionp + fnlen - 7, "TagList")))
- {
- /* xxxTagList function found. Make xxxTags of it
- */
-
- strncpy(tmpfuncnam, functionp, fnlen - 4);
- strcpy (tmpfuncnam + fnlen - 4, "s" );
-
- functionp = tmpfuncnam;
- loops = 0;
- }
- else if((fnlen > 1) && ((functionp[fnlen-1] == 'A') && (functionp[fnlen-2] >= 'a') && (functionp[fnlen-2] <= 'z')))
- {
- /* Not that smart recognition... But you probably
- ** don't want to have a function CreateDA() varargs,
- ** want you?
- **
- ** Recognized are functions that end with 'A' and that
- ** have a lowercase letter before that.
- */
-
- strcpy(tmpfuncnam, functionp);
- tmpfuncnam[fnlen-1] = '\0';
-
- functionp = tmpfuncnam;
- loops = 0;
- }
-
- if(!loops)
- {
- if(mode & DEBUG) puts("Found via internal logic!");
- }
- }
-
- if(loops) for(i=0; p != NULL; i+=2)
- {
- if(!strcmp(p, functionp))
- {
- if(mode & DEBUG) puts("Found!");
-
- functionp = (char *) varargs[i - 1]; /* [i+1] */
- loops = 0;
- break;
- }
-
- /*i += 2;*/
- p = (char *) varargs[i];
- }
- }
- }
-
- offset += 6;
- } /* for(;;) */
-
- if(name) fclose(fd);
-
- fputs("\n\tend\n", lvos);
-
- fclose(lvos);
- }
-
- /* Append '/' to path if needed
- */
-
- static void
- fillpath(char *dirpath)
- {
- int sl = strlen(dirpath);
-
- switch(dirpath[sl-1])
- {
- case ':': /* ':' should be AMIGA-only! This will be commented out. */
- case '/':
- break;
-
- default:
- strcpy(dirpath+sl, "/");
- break;
- }
- }
-
- /* Show program usage
- */
-
- static void Usage(const char *) NORETURN;
-
- static void
- Usage(const char *myname)
- {
- printf("fd2libPPC (c) by Volker Barthelmann / Johnny Teveßen\n"
- "\n"
- " -- Caution: Needs ~5000 byte stack! --\n"
- "\n"
- "Usage : %s [-sd] [-nv] [-o <dir>] [-of <format>]\n"
- " [-d] [-?|--help] [files/pattern]\n"
- "\n"
- " -sd : Use small data model (else large data model)\n"
- " -nv : No varargs logic - ...A and ...TagList will not be detected\n"
- " -o : Specify directory to store source files in\n"
- " -of : C printf style output format to generate compiling\n"
- " script. Three `%%s' are replaced with output file name\n"
- " -d : Turn on debugging/verbose mode\n"
- " -? : Show help/version and quit\n"
- "files : FD files to convert, defaults to stdin\n"
- "\n"
- "Commandline is parsed left-to-right. Specifying\n"
- "\"alib_lib.fd -sd blib_lib.fd\" will result in alib\n"
- "getting large data model.\n",
- myname
- );
-
- exit(0);
- }
-
- /* Remember: ixemul.library does command line expansion, eg.:
- **
- ** redrose# fd2lib -sc -sd /fd/a*_lib.fd
- **
- ** will become:
- **
- ** redrose# fd2lib -sc -sd /fd/amigaguide_lib.fd /fd/asl_lib.fd ...
- **
- */
-
- int
- main(int argc, char **argv)
- {
- int erg = 0 /*EXIT_FAILURE*/;
- int mode = NEWNOTATE | VARGSLOGIC;
- int filesdone = 0;
-
- char outdir[80] = "", outform[250] = "";
-
- if(argc > 1)
- {
- int i;
-
- for(i=1; i<argc; i++)
- {
- if(argv[i][0] == '-')
- {
- /* Parse option */
-
- if( !strcmp(argv[i], "-sd")) mode |= SMALLDATA;
- else if( !strcmp(argv[i], "-nv")) mode &= ~VARGSLOGIC;
- else if( !strcmp(argv[i], "-o" ))
- {
- if(i < (argc-1))
- {
- i ++;
-
- if(strlen(argv[i]) < sizeof(outdir))
- {
- strcpy (outdir, argv[i]);
- fillpath(outdir);
- }
- else
- {
- fprintf(stderr, "Path too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outdir));
- }
- }
- else
- {
- fputs("No path specified after `-o'!\n", stderr);
- }
- }
- else if( !strcmp(argv[i], "-of"))
- {
- if(i < (argc-1))
- {
- i ++;
-
- if(strlen(argv[i]) < sizeof(outform))
- {
- strcpy(outform, argv[i]);
- strcat(outform, "\n" );
- }
- else
- {
- fprintf(stderr, "Format too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outform));
- }
- }
- else
- {
- fputs("No format specified after `-of'!\n", stderr);
- }
- }
- else if( !strcmp(argv[i], "-d" )) mode |= DEBUG;
- else if((!strcmp(argv[i], "-?" )) ||
- (!strcmp(argv[i], "--help"))) Usage(*argv);
- else
- {
- fprintf(stderr, "Unknown option `%s'\n\n", argv[i]);
- Usage(*argv);
- }
- }
- else
- {
- /* Process file */
-
- if(argv[i][0] == '?') Usage(*argv);
- else
- {
- ProcessFD(argv[i], mode, outdir, outform);
- filesdone ++;
- }
- }
- }
- }
-
- if(!filesdone) ProcessFD(NULL, mode, outdir, outform);
-
- return(erg);
- }
-